
import path from 'path'
import crypto from 'crypto'
import ini from 'ini'
import fs from 'fs-extra'
import isJson from 'is-json'
import moment from 'moment'
import _ from 'lodash'
import Rules from '../config/rules'
import logger from './logger'

const salt_len = 12
const ran_num = 8
const ran_str = 'abcdefghijkmnpqrstuvwxyz0123456789ABCDEFGHJKMNPQRSTUVWXYZ@$!%*#?&'

export const loadConfig = (config) => {
  let configInfo = {}
  let configFile = path.resolve(process.cwd(), config)
  try {
    let configStr = fs.readFileSync(configFile, 'utf-8')
    if (isJson(configStr)) {
      configInfo = JSON.parse(configStr)
    }
    else {
      configInfo = ini.parse(configStr)
    }
  } catch (error) {
    
  }
  return configInfo
}

export const loadError = (Code, Message) => {
  let errors = []
  for (let e in Code) {
    errors.push({
      code: Code[e],
      message: Message[e]
    })
  }
  return errors
}

const getAlias = dir => _.upperFirst(dir.match(/[\w\-]+$/)[0].replace(/[\-\_](\w)/g, (x) => x.slice(1).toUpperCase() ))

const getHump = name => name.toLowerCase().replace(/[\-\_](\w)/g, (x) => x.slice(1).toUpperCase() )

export const loadData = (iniFile) => {
  let dataInfo = {}
  let dataFile = path.resolve(process.cwd(), 'data', iniFile)
  try {
    let dataStr = fs.readFileSync(dataFile, 'utf-8')
    if (isJson(dataStr)) {
      dataInfo = JSON.parse(dataStr)
    }
    else {
      dataInfo = ini.parse(dataStr)
    }
  } catch (error) {
    
  }
  return dataInfo
}

export const callback = (resolve, reject, err, doc = null) => {
  if (err) {
    reject(err)
  }
  else {
    resolve(doc)
  }
}

export const random = (len = ran_num, char = ran_str) => {
  let str = ''
  for (let i = 0; i < len; i++) {
    let idx = _.random(0, char.length)
    str += char.slice(idx, idx + 1)
  }
  return str
}

export const md5 = text => crypto.createHash('md5').update(text).digest('hex')
export const sha1 = text => crypto.createHash('sha1').update(text).digest('hex')

const getEncryptPwd = (pwd, salt) => sha1(`${md5(pwd)}^${salt}`)

export const encryptPwd = str => {
  let salt = random(salt_len)
  let encrypt = getEncryptPwd(str, salt)
  return { salt, encrypt }
}

export const validPassword = (pwd, salt, encrypt) => encrypt === getEncryptPwd(pwd, salt)

export const toPageInfo = (page, size) => {
  let parseVal = parseInt(page || 1)
  let val = parseVal === NaN ? 1 : parseVal
  let pageCode = _.isNaN(val) || val < 1 ? 1 : parseVal
  let skipVal = (pageCode - 1) * size
  return {
    pageCode,
    limit: size,
    skip: skipVal
  }
}

export const getMaxPage = (total, size) => Math.ceil((total + size ) / size) - 1

export const currentPage = (page, total, size) => {
  let max_page = getMaxPage(total, size)
  return max_page < page ? max_page : page
}

export const filterRangePicker = (key, query) => {
  if (_.has(query, key)) {
    let picker_time = query[key].split('|')
    let { begin, end } = _.zipObject(['begin', 'end'], picker_time)
    begin = /^(\d+)$/.test(begin) ? _.toInteger(begin) : begin
    end = /^(\d+)$/.test(end) ? _.toInteger(end) : end
    begin = moment(begin).isValid() ? moment(begin).utcOffset(8).format('YYYY-MM-DD HH:mm:ss') : undefined
    end = moment(end).isValid() ? moment(end).utcOffset(8).format('YYYY-MM-DD HH:mm:ss') : undefined
    if (begin && end) {
      return { begin, end }
    }
  }
  return null
}

export const filterFindString = (key, query, field, fuzzy = false) => {
  if (_.has(query, key)) {
    let query_value = query[key].replace(/\s/g, '').split('|')
    let query_arr = []
    for (let item of query_value) {
      !_.isEmpty(item) && query_arr.push(fuzzy ? { [field]: new RegExp(item) } : item)
    }
    if (query_arr.length > 0) {
      return {
        query_arr,
        query_str: query[key].replace(/\s/g, '')
      }
    }
  }
  return null
}

export const validRule = (name, value) => {
  try {
    let rule = Rules[name]
    let pattern = rule.pattern || rule
    let reg = new RegExp(pattern)
    let valid = reg.test(value)
    let size = checkLength(value)
    if (rule.minlength && size < rule.minlength) {
      valid = false
    }
    if (rule.maxlength && size > rule.maxlength) {
      valid = false
    }
    return { valid, message: rule.message || '' }
  } catch (error) {
    logger.error('Rules Error', error)
  }
}

const checkLength = (str) => {
  let size = 0
  if (_.isEmpty(str)) return size
  let arr = str.split('')
  for (let word of arr) {
    size++
    (/[^\x00-\xff]/g.test(word)) && size++
  }
  return size
}